#coding=utf-8
"""iLibM是iLib库的Python对Mongodb的迁移版本
@author:姜源
@license:
@createtime:2013-10-07

1.注意此库用于jy团队的商业项目开发
2.团队内人员可随意使用,严禁对外发布源码
3.团队内人员离开团队后使用此库开发其他商业项目须事先征得jy允许
@contact: jy@cjlu.edu.cn
@version:1.0
@todo:
"""
from web.utils import storage
from loger import *
import traceback
import json

import sys
from pymongo import Connection

reload(sys)
sys.setdefaultencoding('utf8')
def Get_Conn():
    """
    重新获取到数据库连接

    1.它从config.py中获取DATABASE_ARGS参数进行连接

    2.类初始化时调用它获取数据库连接

    3.连接失败时从新调用
    @return: 数据库连接
    """
    try:
        db=Connection().gingertodo
        return db
    except Exception,ex:
        raise ex
def GC_id(tablename):
    """
    从变量表中获取到这个表的自增情况
    如果表名已经存在则获取，然后加1
    如果表名不存在则写入，置1
    """
    result=1

    #id表
    tids=Get_Conn().ids
    rec=tids.find_one({"tablename":tablename})
    if rec:
        rec=storage(rec)
        rec.id+=1
        #更新数据
        tids.update({'tablename':tablename},{'$set':{'id':rec.id}})
    else:
        rec=storage()
        rec.tablename=tablename
        rec.id=1
        tids.insert(rec)
    result=rec.id
    return result
class DalBase(object):
    """
    iLib的Python版本for mongodb
    采用pymongo为基础实现
    """
    db                   = Get_Conn()               #数据库连接

    table_name     = ""                              #数据表名
    table               = None                          #数据表对象
    fields              =  []                                 #数据表非主键字段数组

    def __init__(self,table_name,key_field,fields):
        """
        @rtype : object
        @param table_name: 数据表名称
        @type table_name: 字符类型

        @param key_field: 关键字段 一般为id
        @type key_field: 字符类型

        @param fields: 数据表字段
        @type fields: 字符数组
        """
        self.table_name=table_name
        self.fields=fields
        self.key_field=key_field
        self.table=self.db[table_name]

    def CheckHave(self,filterobj):
        """
        tested ok
        用于根据给定的查询参数确定数据表中是否有数据
        @param whereargs: 参数字典
        @type whereargs: 字典，EX: where="id>0"
        @return:数据的记录数大于1条是返回True否则返回False
        """
        try:
            recs=self.GetRowsByFilterDict(filterobj)
            return recs.count()>0
        except Exception,ex:
            msg = u"iLibM执行CheckHave函数出错,[具体信息]:"+str(traceback.format_exc())+u",\n[参数]:\n"+str(id)+u"\n[数据]:\n"+str(ex)
            LogError(msg)
            raise Exception,msg

    def TestHave(self,id):
        """
        tested ok
        根据主键来判断数据是否已经存在
        @param id: 主键
        @type id: int
        @return:数据的记录数大于1条是返回True否则返回False
        """
        return self.CheckHave({self.key_field:id})

    def GetRowById(self,id):
        """
        tested ok
        根据id来获取一行
        @note:如果获得的结果是多行，则默认取第一行返回
        @param id: 主键
        @type id: int
        @return:一条记录，类型为storage
        """
        try:
            rec=self.table.find_one({self.key_field:id})
            return rec
        except Exception,ex:
            msg=u"iLibM执行GetRowById函数出错,[具体信息]:"+str(traceback.format_exc())+u",\n[参数]:\n"+str(id)+u"\n[数据]:\n"+str(ex)
            LogError(msg)
            raise Exception,msg

    def GetRowByFilterDict(self,filterobj):
        """
             根据过滤字典来获取一个行 tested ok
        """
        try:
            rec=self.table.find_one(filterobj)
            return rec
        except Exception,ex:
            msg=u"iLibM执行GetRowByStrWhere函数出错,[具体信息]:"+str(traceback.format_exc())+u",\n[参数]:\n"+str_where+u"\n[数据]:\n"+str(ex)
            LogError(msg)
            raise Exception,msg

    def GetAll(self):
        """
        获取所有记录 tested ok
        """
        return self.table.find()

    def GetRowsByFilterDict(self,filterobj):
        """根据filterobj条件来获取记录集
        """
        try:
            recs=self.table.find(filterobj)
            return recs
        except Exception,ex:
            msg=u"iLibM执行GetRowsByStrWhere函数出错,[具体信息]:"+str(traceback.format_exc())+u",\n[参数]:\n"+str_where+u"\n[数据]:\n"+str(ex)
            LogError(msg)
            raise Exception,msg

    def DelRowsByFilterDict(self,filterobj):
        """根据filterobj条件来删除记录集
        """
        try:
            i=self.table.remove(filterobj)
            return i
        except Exception,ex:
            msg=u"iLibM执行DelRowsByFilterDict函数出错,[具体信息]:"+str(traceback.format_exc())+u",\n[参数]:\n"+str(ex)
            LogError(msg)
            raise Exception,msg
    def DelRowById(self,id):
        """根据id条件来获取记录集
        @param id: 主键值
        @type id: int
        @return:删除结果
        """
        try:
            self.table.remove({self.key_field:id})
            return True
        except Exception,ex:
            msg=u"iLibM执行DelRowById函数出错,[具体信息]:"+str(traceback.format_exc())+u",\n[参数]:\n"+str(id)+u"\n[数据]:\n"+str(ex)
            LogError(msg)
            raise Exception,msg
    def __Filter(self,value_dict):
        """
        过滤掉不符合数据表结构的数据,返回一个storage
        1.主要用于过滤WebForm采集到的storage属性，将多余数据表字段的属性去掉
        """
        result=storage()
        for key in self.fields:
            if value_dict.get(key,None) is not None:
                result[key]=value_dict.get(key,None)
        return result
    def Save(self,obj):
        """
        保存函数，可将storage对象保存到指定的数据表
        @note:fields中一定要包括id
        @param obj: 需要保存的对象
        @type obj: storage
        """
        try:
            objn=self.__Filter(obj)                                             #过滤掉传入对象中与数据无关的属性,再用于操作数据
            if obj.get(self.key_field,None) is None:                    #要求传入参数中必须包括主键信息
                raise Exception,u"传入数据需要包括数据表的主键属性值"
            else:
                objn[self.key_field]=obj[self.key_field]
                if self.TestHave(obj[self.key_field]):
                    self.table.update({self.key_field:objn[self.key_field]},{'$set':objn})
                else:
                    objn.id=GC_id(self.table_name) #增加了自增id功能

                    self.table.insert(objn)
                    return objn
        except Exception,ex:
            msg=u"iLibM执行Save函数出错,[具体信息]:"+str(traceback.format_exc())+u",\n[参数]:\n"+str(obj)+u"\n[数据]:\n"+str(ex)
            LogError(msg)
            raise Exception,msg

    def UpdateColValue(self,id,col,value):
        """
        tested ok
        更新某列数据值，不论给定值是何值，直接更新
        @param id:数据列的id值
        @param col:列名
        @param value:需要更新的值
        """
        try:
            #通过语句来完成项目值修订
            self.table.update({self.key_field:id},{'$set':{col:value}})
            return value
        except Exception,ex:
            #编码参数
            args=json.dumps((self.table_name,id,col,value))
            msg=u"iLibM执行UpdateColValue函数出错,[具体信息]:"+str(traceback.format_exc())+u",\n[参数]:\nid:"+args+u",\n[数据]:\n"+str(ex)
            LogError(msg)
            return None

    def GetCount(self,filterobj):
        """
        tested ok
        获取指定查询条件下得记录数量
        @param dbwhere: 查询条件 如：where="id>$i",vars={"i":id}
        @type dbwhere: 字典
        """
        try:
            r=self.table.find(filterobj).count()
            return r
        except Exception,ex:
            msg=u"iLibM执行GetCount函数出错,[具体信息]:"+str(traceback.format_exc())
            LogError(msg)
            raise Exception,msg

    def GetPagedRowsByFilterDict(self,pageindex,pagesize,filterobj):
        """
        获取某查询条件下的指定页号数据集
        @note:
        特别注意这里的pageindex从0开始计算，如果计算第一页则需要传入0
        @param pageindex:页号
        @type pageindex:int
        @param pagesize:每页记录数
        @type pagesize:int
        @param dbwhere: 查询条件 如：where="id>$i",vars={"i":id}
        @type dbwhere: 字典
        @return: 记录集,总记录数,总页数
        """
        pageindex=int(pageindex)
        pagesize=int(pagesize)
        #总记录数
        recordercount=self.GetCount(filterobj)
        #总页数
        pagecount = recordercount/pagesize
        if recordercount%pagesize != 0:
            pagecount += 1
        #分页结果
        offset= pageindex *pagesize
        result=self.table.find().skip(offset).limit(pagesize)
        return result,recordercount,pagecount